﻿
Imports System.DateTime
Imports System.Threading
Imports osi.root.constants
Imports osi.root.template
Imports osi.root.envs
Imports osi.root.formation
Imports osi.root.connector
Imports osi.root.lock
Imports osi.root.utils
Imports counter = osi.root.utils.counter

Public Class iqless_threadpool
    Inherits threadpool

    Private Const low_pri_rate As Double = 0
    Private Shared ReadOnly wait_time_ms As Int32 = sixteen_timeslice_length_ms
    Private ReadOnly THREADPOOL_WAIT_TICKS As Int64
    Private ReadOnly THREADPOOL_IDLE_ROUNDS As Int64
    Private ReadOnly q As islimqueue(Of work_info) = Nothing
    Private ReadOnly threads As vector(Of Thread) = Nothing
    'AutoResetEvent is pretty slow
    Private ReadOnly are As AutoResetEvent = Nothing
    Private it As Int32 = 0
    Private ReadOnly typename As String = Nothing

    Private Sub wait_job()
        Interlocked.Increment(it)
        If busy_wait Then
            wait_when(Function() Not (are.WaitOne(0) OrElse stopping()))
        Else
            assert(are.WaitOne() OrElse stopping())
        End If
        'are.WaitOne(wait_time_ms)
        'sleep(wait_time_ms)
        Interlocked.Decrement(it)
    End Sub

    Private Sub set_job()
        'If working_threads() = 0 Then
        '    are.Set()
        'End If
        If it > 0 Then
            are.Set()
        End If
    End Sub

    Protected Overrides Sub queue_job(ByVal wi As work_info)
        assert(Not wi Is Nothing)
        q.push(wi)
        set_job()
    End Sub

    Private Sub worker()
        While True
            Dim wi As work_info = Nothing
            If q.pop(wi) Then
                work_on(wi)
            ElseIf threadpool_trace Then
                Dim startticks As Int64 = 0
                startticks = Now().Ticks()
                wait_job()
                counter.record_time_ticks(THREADPOOL_WAIT_TICKS, startticks)
                counter.increase(THREADPOOL_IDLE_ROUNDS)
            Else
                wait_job()
            End If
        End While
    End Sub

    Private Function typedname(ByVal s As String) As String
        Return strcat(typename, s)
    End Function

    Private Function upper_typedname(ByVal s As String) As String
        Return strtoupper(typedname(s))
    End Function

    Public Overrides Property thread_count() As Int32
        Get
            Return threads.size()
        End Get
        Set(ByVal value As Int32)
            If value <= 0 Then
                value = default_thread_count()
            End If
            If threads.size() > value Then
                [stop]()
                reset_stop_signal()
            End If
            While threads.size() < value
                Dim id As UInt32 = 0
                id = threads.size()
                threads.emplace_back(New Thread(Sub()
                                                    assert(processor_affinity = npos OrElse
                                                           (processor_affinity >= 0 AndAlso
                                                            processor_affinity < Environment.ProcessorCount()))
                                                    If processor_affinity <> npos Then
                                                        loop_set_thread_affinity(processor_affinity +
                                                                                 queue_runner.thread_count +
                                                                                 id)
                                                    End If
                                                    worker()
                                                End Sub))
                Dim t As Thread = Nothing
                t = threads.back()
                If low_pri_rate > 0 Then
                    If threads.size() <= value / (1 + low_pri_rate) Then
                        t.Name() = upper_typedname("_workthread_hi_pri")
                        t.Priority() = ThreadPriority.Highest
                    Else
                        t.Name() = upper_typedname("_workthread_low_pri")
                        t.Priority() = ThreadPriority.Lowest
                    End If
                Else
                    t.Name() = upper_typedname("_workthread")
                End If
                t.Start()
            End While
        End Set
    End Property

    Protected Sub New(ByVal q As islimqueue(Of work_info), Optional ByVal thread_count As Int64 = 0)
        MyBase.New()
        typename = Me.GetType().Name()
        If threadpool_trace Then
            THREADPOOL_WAIT_TICKS = counter.register_average_and_last_average(upper_typedname("_WAIT_TICKS"))
            THREADPOOL_IDLE_ROUNDS = counter.register_rate_and_last_rate(upper_typedname("_IDLE_ROUNDS"))
        End If
        assert(Not q Is Nothing)
        Me.q = q
        threads = New vector(Of Thread)()
        are = New AutoResetEvent(False)
        Me.thread_count() = thread_count
    End Sub

    Protected Overrides Function managed_threads() As Thread()
        Return +threads
    End Function

    Protected Overrides Sub Finalize()
        are.Close()
        MyBase.Finalize()
        GC.KeepAlive(are)
        GC.KeepAlive(threads)
    End Sub
End Class
